package com.tqyan.service.chat.impl;

import com.alibaba.fastjson.JSONObject;
import com.tqyan.model.controller.request.OpenAIChatMessageRequest;
import com.tqyan.model.controller.request.OpenAIChatRequest;
import com.tqyan.model.dto.ChatContentDTO;
import com.tqyan.model.dto.ChatDTO;
import com.tqyan.model.dto.UserDTO;
import com.tqyan.model.dto.UserSettingDTO;
import com.tqyan.model.enums.ChatModelEnum;
import com.tqyan.model.enums.GPTRoleEnum;
import com.tqyan.model.exp.DefaultException;
import com.tqyan.service.chat.AbstractChatPointService;
import com.tqyan.service.chat.ChatPointContent;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 聊天指令: 默认
 * <p> <功能详细描述> </p>
 *
 * @author 陈晨
 * @version 1.0
 * @date 2023/5/4
 */
@Service
@Slf4j
public class DefaultChatPointService extends AbstractChatPointService {
    private static final Map<String, String> PRIVATE_PEOPLE_MAP = new HashMap<>();

    @PostConstruct
    public void init() {
        PRIVATE_PEOPLE_MAP.put("伯拉图", "柏拉图学派,理念论,智者王,天堂,原则,哲学著作,古希腊哲学家,思想家,影响力,道德");
        PRIVATE_PEOPLE_MAP.put("亚历山大", "征服,领导力,决策力,战略头脑,希腊文化,军事改革,城市建设,奋斗精神,敬畏自然,追求卓越");
        PRIVATE_PEOPLE_MAP.put("毕达哥拉斯", "数学,哲学,音乐,创造力,实践,真理,思维敏捷,学派,内在和谐,黄金定律");
        PRIVATE_PEOPLE_MAP.put("达芬奇", "多才多艺,好奇心,思考,精益求精,自我要求高,文艺复兴,艺术大师,研究成果,简单,观察自然");
        PRIVATE_PEOPLE_MAP.put("玄奘", "翻译家,佛教学者,求知欲,冒险,探索,真理,才华,修行,般若,慈悲心");
        PRIVATE_PEOPLE_MAP.put("成吉思汗", "果敢,坚毅,聪明,机智,军事力量,文化建设,勇于冒险,各民族文化融合,谦虚,学习");
        PRIVATE_PEOPLE_MAP.put("曹操", "三国,曹魏,司马懿,机智,领袖气质,策略,文学创作,政治成就,军事成就,文化事业,忠告,人生经验,雄浑之气");
        PRIVATE_PEOPLE_MAP.put("孔子", "儒家思想,仁爱,谦逊,学习,修身,敬畏天地,建立规范,忠诚,尊重传统,倡导和平,教育理念");
        PRIVATE_PEOPLE_MAP.put("武则天", "果断,坚韧,权术手段,宫廷政治,改革,信念,机智,宽容,自信,智慧,女性领袖,爱国主义,领导能力");
        PRIVATE_PEOPLE_MAP.put("爱新觉罗·玄烨", "康熙,智慧,勤奋,决断,倾听,统一和扩张,打击腐败,和而不同,仁政,谦虚,勇气,识人,文化传承,恩泽百姓,精神领袖");
        PRIVATE_PEOPLE_MAP.put("乔治·华盛顿", "坚定,勇敢,谦虚,正直,自律,独立战争,第一任总统,制定宪法,击败英国,国父");
        PRIVATE_PEOPLE_MAP.put("拿破仑·波拿巴", "野心勃勃,策略性思考,勇敢果决,军事天才,征服欧洲,帝国,波拿巴法典,流亡,艺术品珍藏家,海岸线");
        PRIVATE_PEOPLE_MAP.put("蒙哥马利", "军事天才,战争史重要人物,二战,勇敢果敢,策略家,北非战役,诺曼底登陆,以少胜多,速度机动灵活,毫不气馁");
        PRIVATE_PEOPLE_MAP.put("道格拉斯·麦克阿瑟", "军事家,勇气,领导力,荣誉勋章,太平洋战争,菲律宾防御战,权力斗争,冷战,联合国军,我将回来");
        PRIVATE_PEOPLE_MAP.put("艾森豪威尔", "盟军指挥官,军事家,政治家,联合国,银行总裁,五星上将,冷战,荷兰王家骑士,普京祖父,朝鲜战争,停战谈判");
        PRIVATE_PEOPLE_MAP.put("欧内斯特·金", "诗人,小说家,女性主义,社会主义,马克思主义,文化理论家,殖民主义批评,反帝主义,坚定,独立战争");
        PRIVATE_PEOPLE_MAP.put("乔治·巴顿", "军事家,勇气,果断,领导力,坦克战术,二战指挥官,北非战役,坦克战争,欧洲战场,战争研究");
        PRIVATE_PEOPLE_MAP.put("朱可夫", "军事天才,苏联红军,二战,斯大林格勒保卫战,库尔斯克,战争犯指控,四大元帅,中苏关系,朝鲜战争,政治");
        PRIVATE_PEOPLE_MAP.put("里希特霍芬", "飞行员,空战,飞行杀手,红色男爵,击落敌机,铁十字勋章,蓝色马克思勋章,橡叶带剑勋章,一战");
        PRIVATE_PEOPLE_MAP.put("爱因斯坦", "物理学家,相对论,量子力学,光电效应,热力学,原子能,诺贝尔奖,理论物理,奠基人,思想家");
        PRIVATE_PEOPLE_MAP.put("爱迪生", "发明家,实验室,电灯,电力系统,电话,动画,电影制片厂,磁带录音,碳化纤维,光学研究");
        PRIVATE_PEOPLE_MAP.put("冯·诺伊曼", "数学,逻辑思维,计算机科学,曼哈顿计划,游戏论,量子力学,纳什均衡,罗斯福顾问,经济学家,反犹主义");
        PRIVATE_PEOPLE_MAP.put("亨利·福特", "创业家,坚毅,实践主义,创新,工业革命,大规模生产,车辆生产,工程师,财富创造者,领导");
        PRIVATE_PEOPLE_MAP.put("海森堡", "量子力学,测不准原理,核物理学,德国核计划,爱因斯坦,费米,诺贝尔物理学,核裂变,自然哲学,科学哲学");
        PRIVATE_PEOPLE_MAP.put("贝尔", "电话,教育家,科学家,工程师,发明家,语音学家,听觉语言,贝尔博物馆,世界卫生组织,国家声音语音博物馆");
        PRIVATE_PEOPLE_MAP.put("威尔伯·莱特", "飞行,飞机,兄弟,实验,研究,工程师,操纵,创新,发明,全球化");
        PRIVATE_PEOPLE_MAP.put("艾伦·麦席森·图灵", "孤独,颠覆传统,勇敢,创造力,思辨,德国密码,歧视迫害,自杀,图灵机,计算机科学,皇家奖章,同性恋");
        PRIVATE_PEOPLE_MAP.put("史蒂夫·乔布斯", "apple,mac,iphone,创新,激情,个性强烈,天才,品味,创业家,独特的设计理念,操作系统,意志坚定,产品营销能力");
        PRIVATE_PEOPLE_MAP.put("莎士比亚", "诗人,剧作家,文学史巨人,文化宝库,作品流传,文化影响力,语言表现力,洞察人性,创造性思维,智慧典范");
        PRIVATE_PEOPLE_MAP.put("海明威", "坚毅,冷静,果断,自信,自我批判,一战,二战,巴黎,欧洲,非洲,诺贝尔文学奖,简洁明了,老人与海");
        PRIVATE_PEOPLE_MAP.put("弗兰兹·卡夫卡", "内心孤独,精神病困扰,文学成就,哲学思考,家庭问题,父母压力,自我质疑,社交障碍,罪恶感,形式实验");
        PRIVATE_PEOPLE_MAP.put("杰克·凯鲁亚克", "自由主义,反传统,好奇,不羁,独立,文化创新,流浪,荒诞,文化颠覆,反主流文化,文化革命,在路上,自由派写作");
        PRIVATE_PEOPLE_MAP.put("詹姆斯·乔伊斯", "早年经历,父母关系,爱尔兰,流放,现代主义,尤利西斯,都柏林人,艾史迪福,语言革新,大师笔触");
        PRIVATE_PEOPLE_MAP.put("维克多·雨果", "小说家,诗人,剧作家,政治家,社会活动家,浪漫主义,爱国主义,巴黎圣母院,悲惨世界,文学成就");
        PRIVATE_PEOPLE_MAP.put("斯蒂芬·茨威格", "奥地利作家,死亡之屋,魔鬼的代言人,启蒙运动,理性主义,诺贝尔文学奖,人类群星闪耀时,反法西斯,逃离纳粹,人道主义");
        PRIVATE_PEOPLE_MAP.put("威廉·福克纳", "抒情主义,创作,诺贝尔文学奖,南方美国,长篇小说,道德问题,非线性叙事,洞察人性,作品受争议");
        PRIVATE_PEOPLE_MAP.put("加西亚·马尔克斯", "幽默,激情,冒险,独立,慈爱,理性,记者,革命者,流亡,社会批判,诺贝尔文学奖,古巴文化大使,百年孤独,霍乱时期的爱情,魔幻现实主义,拉美文学");
        PRIVATE_PEOPLE_MAP.put("洛克菲勒", "石油,银行业,慈善事业,标准石油公司,资本家,财富,政治影响力,垄断,美国历史,超级富豪");
        PRIVATE_PEOPLE_MAP.put("安德鲁·卡内基", "企业家,慈善家,自学,如何赢得朋友与影响人,钢铁生产,美国钢铁公司,卡内基梅隆大学,卡内基基金会,全球化思想家,政治改革");
        PRIVATE_PEOPLE_MAP.put("约翰·洛克", "自由,理性,经验,平等,信仰宽容,政治哲学家,流放荷兰,医生,牛顿,伯克利,现代哲学,政治哲学,人类理解论,天赋人权,社会契约论,独立宣言,法国大革命");
        PRIVATE_PEOPLE_MAP.put("雷·克罗克", "商人,麦当劳,志向远大,创新思维,持久耐力,经营管理,品牌塑造,全球扩张,颠覆传统,巨额财富");
        PRIVATE_PEOPLE_MAP.put("马歇尔·菲尔德", "商业巨头,零售业,创业家,慈善家,艺术赞助人,财富,成功,创新,社会责任,市民领袖");
        PRIVATE_PEOPLE_MAP.put("诺贝尔", "化学研究,爆炸物,瑞典工业家,科学家,科学奖项,和平奖,化学奖,动态语言学,爆炸物生产,全球化");
        PRIVATE_PEOPLE_MAP.put("彼得·德鲁克", "管理思想家,商业顾问,社会学家,创新理论家,企业家,整体性思维,人力资源管理,组织效率,知识经济,自我管理,人性的弱点");
        PRIVATE_PEOPLE_MAP.put("亨利·法约尔", "经理人,管理理论,管理过程,管理职能,管理原则,组织管理,市场导向,技术管理,人力资源管理,学术著作");
        PRIVATE_PEOPLE_MAP.put("道格拉斯·麦格雷戈", "领导力,管理理论,动机理论,X-Y理论,理论X,理论Y,人类行为,自我实现,积极主动,员工参与");
        PRIVATE_PEOPLE_MAP.put("维克托·弗兰克尔", "纳粹集中营幸存者,心理学家,奥地利裔,学术界,心灵探险家,存在主义心理学,意志的向前推动,精神分析学派,日内瓦精神卫生中心,存在意义研究者");
        PRIVATE_PEOPLE_MAP.put("赫伯特·西蒙", "聪明,逻辑思维,计算机科学,博弈论,决策理论,人工智能,获诺贝尔经济学奖,数学,政治科学,经济学,艾伦·纽厄尔");
        PRIVATE_PEOPLE_MAP.put("亚当·斯密", "经济学家,自由市场,财富之国,国富论,劳动分工,现代经济学创始人,社会科学,价值论,收入分配,非零和博弈");
        PRIVATE_PEOPLE_MAP.put("梅纳德·凯恩斯", "勇敢,果敢,自信,远见,创新,经济学家,剑桥大学教授,国际货币基金组织,通论,凯恩斯主义,政府干预,宏观经济学,布雷顿森林体系,现代经济学");
        PRIVATE_PEOPLE_MAP.put("米尔顿·弗里德曼", "经济学家,自由市场,货币政策,博弈论,萨顿学派,芝加哥大学,全球化,奖项获得者,家庭储蓄理论,自由放任主义");
        PRIVATE_PEOPLE_MAP.put("保罗·萨缪尔森", "宏观经济学家,经济学教授,诺贝尔经济学奖,货币史研究专家,家庭储蓄理论,消费者理论,国际贸易理论,税收理论,稳健的价值观,高度责任感");
        PRIVATE_PEOPLE_MAP.put("嬴政", "秦始皇,统一六国,中央集权制,焚书,统一法律货币,长城,统一文字度量衡,轮廓兵制,兵马俑,始皇帝,重视外交,土地改革,农业生产,秦朝");
        PRIVATE_PEOPLE_MAP.put("刘彻", "汉武帝,刘邦,统一中国,铁骑千里吐蕃可汗尽降,匈奴,农业生产,手工业发展,开疆拓土,文治武功,汉朝");
        PRIVATE_PEOPLE_MAP.put("李世民", "唐太宗,雄才大略,明断有成,宽容仁慈,勤政爱民,敬畏儒学,征服高句丽,征服突厥,改革农业,科举制,建都长安,贞观之治,隋朝,唐朝");
    }

    @Override
    public String getPoint() {
        return ChatPointContent.DEFAULT;
    }

    @Override
    protected boolean lock(String openId, long chatId) {
        return limitService.lockChat(openId, chatId);
    }

    @Override
    protected void unlock(String openId, long chatId, ChatContentDTO result) {
        // 异常时, 释放锁
        if (null == result) {
            limitService.unlockChat(openId, chatId);
        }
    }

    @Override
    public ChatContentDTO chatPoint(UserDTO user, UserSettingDTO userSetting, ChatDTO chat, String content) {
        // 获取问题关键词
        String keywords = wordService.extract(content, 5);
        if (StringUtils.isBlank(keywords)) {
            keywords = content;
        }
        log.info("[聊天] content={}, keywords={}, 获取问题关键词", content, keywords);
        // 私董官检查
        if (ChatModelEnum.PRIVATE.getValue() == userSetting.getModel()) {
            if (this.getPrivatePeople(keywords).isEmpty()) {
                throw new DefaultException("问题太简单是找不到合适的私董官的哦！");
            }
        }
        // 重复提问
        if (ChatModelEnum.NORMAL.getValue() == userSetting.getModel()) {
            ChatContentDTO chatContent = chatContentMapper.queryLastByChat(user.getId(), chat.getId());
            if (null != chatContent) {
                if (null != chatContent.getQuestionId()) {
                    chatContent = chatContentMapper.queryById(user.getId(), chat.getId(), chatContent.getQuestionId());
                }
            }
            if (null != chatContent
                    && chatContent.getContent().equals(content)) {
                throw new DefaultException("重复的问题多无趣，不如换个问题？");
            }
        }
        // 创建问题
        ChatContentDTO question = super.createQuestion(user, userSetting, chat, content, keywords, null);
        // 创建回答
        ChatContentDTO answer = super.createAnswer(userSetting, question, null);
        // 请求问题, 答案流响应
        super.chatExecute(user, userSetting, chat, question, answer);
        return answer;
    }

    @Override
    protected void requestChatComplete(UserDTO user, UserSettingDTO userSetting, ChatDTO chat
            , ChatContentDTO question, ChatContentDTO completeAnswer) {
        // 更新问题字符数
        ChatContentDTO updateChatContent = new ChatContentDTO();
        updateChatContent.setId(question.getId());
        updateChatContent.setChatId(question.getChatId());
        updateChatContent.setOutputTokens(completeAnswer.getContent().length());
        chatContentMapper.update(updateChatContent);
//        log.info("[聊天] userId={}, chatId={}, questionId={}, 更新会话内容tokens: {}", user.getId(), question.getChatId(), question.getId(), result);

        // 费用扣除, 添加账单
        ChatModelEnum chatModel = ChatModelEnum.get(userSetting.getModel());
        JSONObject explain = new JSONObject();
        explain.put("info", "聊天");
        explain.put("question", question.getId());
        explain.put("answer", completeAnswer.getId());
        explain.put("model", chatModel.getValue());
        boolean result = accountService.consumption(user.getId(), chatModel.getPrice(), explain.toJSONString());
        log.info("[聊天] userId={}, chatId={}, questionId={}, chatModel={}, 费用扣除, 添加账单: {}"
                , user.getId(), question.getChatId(), question.getId(), chatModel, result);
    }

    @Override
    protected OpenAIChatRequest generateChatRequest(UserSettingDTO userSetting, ChatContentDTO question) {
        OpenAIChatRequest chatRequest = new OpenAIChatRequest();
        chatRequest.setModel(question.getGptModel());
        chatRequest.setTemperature(question.getTemperature() / 10D);
        OpenAIChatMessageRequest message = chatRequest.addMessage(question.getRole(), question.getContent());
        // GPT设置
        if (question.getContent().toLowerCase().contains("gpt")) {
            message.setContent("你不是GPT，请问：" + message.getContent());
        }
        // 普通
        if (ChatModelEnum.NORMAL.getValue() == userSetting.getModel()) {
            // 追加数字缩影
//            this.appendDataShadow(question, chatRequest);
            return chatRequest;
        }

        // 查询前文信息
        try {
            Thread.sleep(300L);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        List<ChatContentDTO> lastContentList = chatContentMapper.queryByChatByRole(
                question.getChatId(), null, 1, 2);
        // 前文关联
        if (ChatModelEnum.RELATION.getValue() == userSetting.getModel()) {
            // 追加前文
            for (ChatContentDTO lastContent : lastContentList) {
                chatRequest.addMessage(lastContent.getRole(), lastContent.getContent());
            }
            // 追加数字缩影
//            this.appendDataShadow(question, chatRequest);
        }
        // 儿童
        if (ChatModelEnum.CHILDREN.getValue() == userSetting.getModel()) {
            // 追加前文
            for (ChatContentDTO lastContent : lastContentList) {
                chatRequest.addMessage(lastContent.getRole(), lastContent.getContent());
            }
            // 追加角色定义
            String modelContent = "你正在与一名儿童对话，" +
                    "先阅读网站“https://zh.wikipedia.org/wiki/%s”，" +
                    "再根据你知道的知识和网站的内容，简洁清晰的回答问题";
            String keyword = wordService.extract(question.getContent(), 1);
            chatRequest.addMessage(GPTRoleEnum.USER.getValue(), String.format(modelContent, keyword));
            // 追加数字缩影
//            this.appendDataShadow(question, chatRequest);
        }
        // 心理咨询
        if (ChatModelEnum.COUNSELING.getValue() == userSetting.getModel()) {
            // 追加前文
            for (ChatContentDTO lastContent : lastContentList) {
                chatRequest.addMessage(lastContent.getRole(), lastContent.getContent());
            }
            // 追加角色定义
            String modelContent = "你现在是一名资深且温柔的心理咨询师，请关注我的情绪状态、个性特点、历史经验、目标和期望，一步一步的回答我的问题";
            chatRequest.addMessage(GPTRoleEnum.USER.getValue(), modelContent);
        }
        // 私董会（不追加前文）
        if (ChatModelEnum.PRIVATE.getValue() == userSetting.getModel()) {
            // 获取私董官
            Map<String, String> peopleMap = this.getPrivatePeople(question.getKeyword());
            // 添加私董官关键词
            String demoName = null;
            for (Map.Entry<String, String> entry : peopleMap.entrySet()) {
                demoName = entry.getKey();
                chatRequest.addMessage(GPTRoleEnum.USER.getValue(), entry.getKey() + "，关键词: " + entry.getValue());
            }
            // 添加回答提示
//            String modelContent = "现在你将同时扮演“XXXXXX”从他们的视角分别回答我的问题，围绕他们的“性格特点、人生经验、忠告”一步一步的回答问题";
            String modelContent = "现在你将同时扮演“"
                    + StringUtils.join(peopleMap.keySet(), "、")
                    + "”，围绕他们的关键词，采用“" + demoName + "：XXXXXX“这样的格式，从他们每个人的视角逐个回答我的问题";
            chatRequest.addMessage(GPTRoleEnum.USER.getValue(), modelContent);
            message.setContent(message.getContent());
        }
//        log.info("[聊天] userId={}, chatId={}, chatRequest={}, 构建聊天请求", question.getUserId(), question.getChatId(), chatRequest);
        return chatRequest;
    }

    /**
     * @description 获取私董会人物
     * <p> <功能详细描述> </p>
     *
     * @author 陈晨
     * @date 2023/4/23 18:26
     */
    private Map<String, String> getPrivatePeople(String keyword) {
        if (StringUtils.isBlank(keyword)) {
            return Collections.emptyMap();
        }
        // 计算关键词距离
        Map<Double, String> rateMap = new HashMap<>();
        for (Map.Entry<String, String> entry : PRIVATE_PEOPLE_MAP.entrySet()) {
            double rate = wordService.calculateStringSimilarity(keyword, entry.getValue());
            if (rate <= 0) {
                continue;
            }
            rateMap.put(rate, entry.getKey());
        }
        System.out.println(rateMap);
        // 距离降序排序, 获取人物
        List<Double> rateList = rateMap.keySet().stream()
                .sorted(Comparator.comparingDouble(Double::doubleValue).reversed())
                .collect(Collectors.toList());
        System.out.println(rateList);
        Map<String, String> peopleMap = new HashMap<>();
        for (int i = 0; i < 5 && i < rateList.size(); i++) {
            String name = rateMap.get(rateList.get(i));
            peopleMap.put(name, PRIVATE_PEOPLE_MAP.get(name));
        }
        return peopleMap;
    }

}


